package com.ak.game.netty;

import com.ak.game.service.PnGameService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class NettyWebSocketServerRunner implements CommandLineRunner {
    @Value("${netty.websocket.port}")
    private int port;

    @Value("${netty.websocket.path}")
    private String websocketPath;

    @Autowired
    private PnGameService gameService;

    @Override
    public void run(String... args) throws Exception {
        //创建用于接收进来的连接的事件循环组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //创建用于处理已经被接收的连接的事件循环组
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //初始化服务器端的引导类，配置服务器端的NIO线程组等相关参数
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //设置两个NioEventLoopGroup，分别用于接受连接和处理连接上的读写操作
            serverBootstrap.group(bossGroup, workerGroup)
                    //指定NIO的模式，用于非阻塞的网络通讯
                    .channel(NioServerSocketChannel.class)
                    //设置ChannelInitializer，用于配置新连接的数据处理流程，这里是WebSocket的初始化器
                    .childHandler(new WebSocketChannelInitializer(websocketPath, gameService)) //自定义ChannelInitializer
                    //设置TCP缓冲区 backlog，用于处理连接请求队列的大小
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //设置保持活动连接状态，心跳保活机制
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            //绑定服务器端口并同步等待直到绑定完成
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            //输出服务启动成功的日志信息
            System.out.println("Netty WebSocket 服务启动成功 端口号:" + port);
            //等待服务端口关闭的future，即等待服务器关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            //关闭工作线程组和接收线程组
            workerGroup.shutdownGracefully();
            System.out.println("关闭工作线程组");
            bossGroup.shutdownGracefully();
            System.out.println("关闭接收线程组");
        }
    }
}
